#include "RulesProcessingUserMode.h"
#include<iostream>

void EnumMultiSZValue(const std::wstring& wstrKey, const std::wstring& wstrValue, IMultiSZObserver* pObserver)
{
    //Get register key
    HKEY hKeyTemp = NULL;
    LONG lResult=RegOpenKeyExW(HKEY_LOCAL_MACHINE, wstrKey.c_str(), 0, KEY_ALL_ACCESS, &hKeyTemp);

    if(lResult != ERROR_SUCCESS)
    {
        throw std::runtime_error("Error key opening!");
    }

    KeyGuard keyGuard(hKeyTemp);
 
    //Read value from the register
    DWORD dwRegetPath=0;
    DWORD dwType=0;

    LONG lRes=RegQueryValueExW(keyGuard.getKey(), wstrValue.c_str(), NULL, &dwType, 0, &dwRegetPath);

    if(lRes!=ERROR_SUCCESS)
    {
        throw std::runtime_error("Error value reading!");
    }

    if(dwType!=REG_MULTI_SZ)
    {
        throw std::runtime_error("Error value type!");
    }

    std::vector<unsigned char> vectReget(dwRegetPath);

    LONG lResRead=RegQueryValueExW(keyGuard.getKey(), wstrValue.c_str(), NULL, 0, &vectReget.at(0), &dwRegetPath);

    if(lResRead!=ERROR_SUCCESS)
    {
       throw std::runtime_error("Error value reading!");
    }

    //Convert char vector to string vector
    std::wstring wstrBuf(reinterpret_cast<wchar_t*>(&vectReget.at(0)), dwRegetPath);

    for(DWORD i=0, j=0;i<dwRegetPath;++i)
    {
        if(wstrBuf.at(i)=='\0')
        {
            std::wstring wstrTemp(wstrBuf.substr(j, i-j));

            pObserver->OnMultiSZItemFound(wstrTemp);

            j=++i;
        }

        if (i+1 == dwRegetPath || wstrBuf.at(i) == wstrBuf.at(i+1) && wstrBuf.at(i) == 0)
        {
            break;
            }
    }
}

void ConvertWStringVectorToRaw(const std::vector<std::wstring>& vwsWStringVector, std::vector<unsigned char>* pVectNewValue)
{
    pVectNewValue->clear();

    for (std::vector<std::wstring>::const_iterator iIt = vwsWStringVector.begin();
         iIt != vwsWStringVector.end();
         ++iIt)
    {
        pVectNewValue->insert(pVectNewValue->end(),
                              reinterpret_cast<const char*>(iIt->c_str()),
                              reinterpret_cast<const char*>(iIt->c_str()) + iIt->size() * sizeof(wchar_t));

        // size of wchar_t is equal to 2 bytes, so we need to add '\0' twice
        pVectNewValue->push_back('\0');
        pVectNewValue->push_back('\0');
    }

    pVectNewValue->push_back('\0');
    pVectNewValue->push_back('\0');
}

void WriteMultiSZValue (const std::wstring& wstrKey, const std::wstring& wstrValue, const std::vector<std::wstring>& vwsMultiSZItems)
{
    //Transform string vector to raw data vector
    std::vector<unsigned char> vectNewValue;

    ConvertWStringVectorToRaw(vwsMultiSZItems, &vectNewValue);

    //Get register key
    HKEY hKeyTemp = NULL;
    LONG lResult=RegOpenKeyExW(HKEY_LOCAL_MACHINE, &(wstrKey.c_str()[0]), 0, KEY_ALL_ACCESS, &hKeyTemp);

    KeyGuard keyGuard(hKeyTemp);
    
    if(lResult!=ERROR_SUCCESS)
    {
        throw std::runtime_error("Error key opening!");
    }

    //Set new value to register parameter
    LONG lRes=RegSetValueExW(keyGuard.getKey(), &(wstrValue.c_str()[0]), 0, REG_MULTI_SZ, &vectNewValue.at(0), vectNewValue.size());
        
    if(lRes!=ERROR_SUCCESS)
    {
       throw std::runtime_error("Error value adding!");
    }
}